package zmee.common.allhelper;

import kd.bos.algo.*;
import kd.bos.algo.input.CollectionInput;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.entity.LocaleString;
import kd.bos.dataentity.resource.ResManager;
import kd.bos.entity.MainEntityType;
import kd.bos.entity.filter.FilterField;
import kd.bos.entity.property.BasedataProp;
import kd.bos.entity.report.*;
import kd.bos.entity.report.parser.IParser;
import kd.bos.entity.report.parser.QFilterParserFactory;
import kd.bos.exception.BosErrorCode;
import kd.bos.exception.KDBizException;
import kd.bos.exception.KDException;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.report.events.SortAndFilterEvent;
import kd.bos.servicehelper.MetadataServiceHelper;
import kd.bos.servicehelper.QueryServiceHelper;
import org.apache.commons.lang.StringUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author wb_sisen_yang
 * @createTime 2022-06-20 10:08
 * @description 报表表头过滤器创建方法
 */
public class ReportTableHeadHelper {

    private static final String[] qfilterCompareType = {"is null","is not null"};

    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
    private static final String KEY_AND = " and ";

    /* ------------------------------------- 添加过滤、排序字段 - Start ------------------------------------- */
    /**
     * 添加报表表头过滤、筛选字段
     * 操作步骤：在报表的表单插件中 重写setSortAndFilter 方法
     * @param allColumns 方法自带参数
     * @param addSortAndFilterArray 需要添加过滤的字段数组
     */
    public static void setSortAndFilter(List<SortAndFilterEvent> allColumns, String[] addSortAndFilterArray) {
        List<String> addSortAndFilterList = Arrays.asList(addSortAndFilterArray);

        for(SortAndFilterEvent event : allColumns){
            if(addSortAndFilterList.contains(event.getColumnName())){
                event.setSort(true);
                event.setFilter(true);
            }
        }
    }

    public static DataSet refreshDataSet(ReportQueryParam reportQueryParam, DataSet dataSet, String billnumber) {
        //表头字段排序和搜索代码---------------------
        String sortInfo = reportQueryParam.getSortInfo();//获取升降序字段
        StringBuilder sb = new StringBuilder();//拼接所有过滤条件
        //表头字段的所有过滤条件(不包含报表常用过滤条件字段)
        List<QFilter> headFilters = reportQueryParam.getFilter().getHeadFilters();
        //获取报表原始界面模型
        MainEntityType dataEntityType = MetadataServiceHelper.getDataEntityType(billnumber);
        if (dataEntityType != null) {
            //遍历单头过滤条件
            for (QFilter headFilter : headFilters) {
                String property = headFilter.getProperty();//字段表头头标识
                Object value = headFilter.getValue();//过滤值
                String cp = headFilter.getCP();//比较类型 “=”、“like”
                FilterField filterField = FilterField.create(dataEntityType, property);
                String refEntityId = filterField.getRefEntityId();//字段所引用的实体对象
                if (StringUtils.isNotEmpty(refEntityId)) {//说明为基础资料
                    //基础资料的过滤判断
                    QFilter qFilter = new QFilter(((BasedataProp) filterField.getFieldProp()).getDisplayProp(), cp, value);
                    DynamicObjectCollection datas = QueryServiceHelper.query(refEntityId, "id", new QFilter[]{qFilter});
                    //根据条件查询符合条件的id
                    List<Object> ids = datas.stream().map(v -> v.get("id")).collect(Collectors.toList());
                    if (ids.size() > 0) {
                        //拼接条件，如果是集合，集合转String后要将 [] 替换成 (),多个后面还需要拼接KEY_AND
                        sb.append(property).append(" in ").append(ids.toString().replace("[", "(").replace("]", ")")).append(KEY_AND);
                    } else {
                        //如果符合条件的id没有，说明符合条件的数据也没有，个人想法暂时默认给id一个值，如果是直接跟字符串比较，可能会报错
                        sb.append(property).append(" = 1 and ");
                    }
                } else {
                    int fieldType = filterField.getFieldType();//字段类型
                    if (fieldType == 93) {//日期字段搜索过滤
                        dateFilterStr(sb, headFilter, property, value, cp);
                    } else if (fieldType == -9) {
                        //文本为空 不为空处理
                        if (cp.equals("is null") ) {
                            if (headFilters.size() > 1) {
                                sb.append(headFilter.toString()).append(KEY_AND);
                            } else {
                                sb.append(headFilter.toString().replace("(", "").replace(")", "")).append(KEY_AND);
                            }
                        } else {
                            sb.append(headFilter.toString()).append(KEY_AND);
                        }
                    } else {
                        //如果不是基础资料类型的字段，需要重新根据字段类型转换过滤值
                        QFilter qFilterBySqlTypes = getQFilterBySqlTypes(property, cp, fieldType, value.toString());
                        sb.append(qFilterBySqlTypes.toString()).append(KEY_AND);
                    }
                }
            }
            String sbStr = sb.toString();
            String filterStr = StringUtils.isNotEmpty(sbStr) ? sbStr.substring(0, sbStr.length() - 5).replace("null ''", "null ") : null;
            if (StringUtils.isNotEmpty(filterStr)) {//搜索过滤
                dataSet = dataSet.copy().filter(filterStr);
            }
            if (StringUtils.isNotEmpty(sortInfo)) {//字段排序
                dataSet = dataSet.copy().orderBy(new String[]{sortInfo});
            }
        }
        return dataSet;
    }
    /**
     * @param sb
     * @param headFilter
     * @param property
     * @param value
     * @param cp
     * @return void
     * @Description 日期字段搜索过滤
     * @Author jiang
     * @Date 2022-03-14 13:49
     */
    private static void dateFilterStr(StringBuilder sb, QFilter headFilter, String property, Object value, String cp) {
        if (value.getClass().getSimpleName().equals("Date")) { //日期类型
            Date startDate = (Date) value;
            int startInt = Integer.parseInt(sdf.format(startDate));
            //日期过滤需要转出Int类型再比较
            sb.append(" Cast(to_char(").append(property).append(",'yyyyMMdd') as Integer) ").append(cp).append(" ").append(startInt).append(KEY_AND);
            List<QFilter.QFilterNest> nests = headFilter.getNests(true);//合并条件
            for (QFilter.QFilterNest nest : nests) {//拼接合并过滤条件
                String nestProperty = nest.getFilter().getProperty();
                String nestCP = nest.getFilter().getCP();
                Date endDate = (Date) nest.getFilter().getValue();
                int endInt = Integer.parseInt(sdf.format(endDate));
                sb.append(" Cast(to_char(").append(nestProperty).append(",'yyyyMMdd') as Integer) ").append(nestCP).append(" ").append(endInt).append(KEY_AND);
            }
        } else if (value.getClass().getSimpleName().equals("String")) { //等于具体某一天  是字符串
            int start = Integer.parseInt(((String) value).replace("-", ""));
            sb.append(" Cast(to_char(").append(property).append(",'yyyyMMdd') as Integer) ").append(cp).append(" ").append(start).append(KEY_AND);
        }
    }
    private static QFilter getQFilterBySqlTypes(String sFilter, String operater, int fieldType, String value) {
        QFilter qFilter = null;
        if (fieldType == 1) {//复选框
            String[] split = ((String) value).replace("[", "").replace("]", "").split(",");
            List<Boolean> bList = new ArrayList<>(2);
            for (String s : split) {
                if (s.trim().equals("0")) {
                    bList.add(false);
                } else if (s.trim().equals("1")) {
                    bList.add(true);
                }
            }
            qFilter = new QFilter(sFilter, operater, bList);
        } else if (fieldType == 5) {
            qFilter = new QFilter(sFilter, operater, parseShort(value));
        } else if (fieldType == -6) {
            qFilter = new QFilter(sFilter, operater, parseByte(value));
        } else if (fieldType == 4) {
            qFilter = new QFilter(sFilter, operater, parseInt(value));
        } else if (fieldType == -5) {
            qFilter = new QFilter(sFilter, operater, parseLong(value));
        } else if (fieldType == 7) {
            qFilter = new QFilter(sFilter, operater, parseBigDecimal(value));
        } else if (fieldType == 12) {//下拉选项
            String[] split = ((String) value).replace("[", "").replace("]", "").split(",");
            qFilter = new QFilter(sFilter, operater, split);
        } else if (fieldType != 6 && fieldType != 8) {
            if (fieldType != 3 && fieldType != 2) {
                if (fieldType == -7) {
                    qFilter = new QFilter(sFilter, operater, parseBoolean(value));
                } else {
                    qFilter = new QFilter(sFilter, operater, value);
                }
            } else {
                qFilter = new QFilter(sFilter, operater, parseBigDecimal(value));
            }
        } else {
            qFilter = new QFilter(sFilter, operater, parseBigDecimal(value));
        }

        return qFilter;

    }
    public static short parseShort(String value) {
        try {
            return Short.parseShort(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("输入内容不在-32768到32767之间", "this_0", "bos-entity-core", new Object[0])});
        }
    }
    public static byte parseByte(String value) {
        try {
            return Byte.parseByte(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("输入内容不在-128到127之间", "this_1", "bos-entity-core", new Object[0])});
        }
    }
    public static int parseInt(String value) {
        try {
            return Integer.parseInt(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("输入内容不在-2147483648到2147483647之间", "this_2", "bos-entity-core", new Object[0])});
        }
    }
    public static long parseLong(String value) {
        try {
            return Long.parseLong(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("输入内容不在-9223372036854775808到9223372036854775807之间", "this_3", "bos-entity-core", new Object[0])});
        }
    }
    public static float parseFloat(String value) {
        try {
            return Float.parseFloat(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("不是有效的浮点数", "this_4", "bos-entity-core", new Object[0])});
        }
    }
    @Deprecated
    public static double parseDouble(String value) {
        try {
            return Double.parseDouble(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("不是有效的双精度数字", "this_5", "bos-entity-core", new Object[0])});
        }
    }
    public static BigDecimal parseBigDecimal(String value) {
        try {
            return new BigDecimal(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("不是有效的双精度数字", "this_5", "bos-entity-core", new Object[0])});
        }
    }
    public static boolean parseBoolean(String value) {
        try {
            return Boolean.parseBoolean(value);
        } catch (NumberFormatException var2) {
            throw new KDBizException(BosErrorCode.filterSqlBuilder, new Object[]{ResManager.loadKDString("不是有效的布尔类型", "this_6", "bos-entity-core", new Object[0])});
        }
    }

    /**
     * 将filter转换为dataset.filter过滤数据
     */
    public static DataSet getDataSetFilter(DataSet dataSet, ReportQueryParam queryParam,String[] numberArray,String[] nameArray){
        String tableHeadQfilterStr = getTableHeadQfilterStr(dataSet,queryParam, numberArray, nameArray);
        if(StringUtils.isNotEmpty(tableHeadQfilterStr)){
            dataSet = dataSet.filter(tableHeadQfilterStr);
        }
        return dataSet;
    }
    /**
     * 获取所有的过滤条件
     * @param queryParam
     * @param numberArray
     * @param nameArray
     * @return
     */
    private static String getTableHeadQfilterStr(DataSet dataSet,ReportQueryParam queryParam, String[] numberArray, String[] nameArray){
        List<String> qfilterStrList = new ArrayList<>();
        List<String> numberList = numberArray == null ? new ArrayList<>() : Arrays.asList(numberArray);
        List<String> nameList = numberArray == null ? new ArrayList<>() : Arrays.asList(nameArray);
        List<FilterItemInfo> tableHeadFilterItems = queryParam.getFilter().getTableHeadFilterItems();
        for(FilterItemInfo itemInfo : tableHeadFilterItems){
            String propName = itemInfo.getPropName();
            String compareType = itemInfo.getCompareType();
            propName = numberList.contains(propName) ? String.format("%s.number",propName) : propName;
            propName = nameList.contains(propName) ? String.format("%s.name",propName) : propName;
            IParser qFilterProcessor = QFilterParserFactory.createQFilterProcessor(compareType);
            QFilter qFilter = qFilterProcessor.buildQFilterByFilterItem(itemInfo);
            qFilter.__setProperty(propName);
            getDataSetFilter(dataSet,qfilterStrList,qFilter,propName);
        }
        return String.join(" and ",qfilterStrList);
    }
    /**
     * 将dataset.filter转换为filter过滤数据
     * @param qFilter
     */
    private static void getDataSetFilter(DataSet dataSet,List<String> qfilterStrList,QFilter qFilter,String propName){
        List<String> qFilterList = new ArrayList<>();
        if(qFilter == null){
            return;
        }
        int num = getDataSetFilter(dataSet,qFilterList,qFilter,0);
        List<QFilter.QFilterNest> nests = qFilter.getNests(true);
        for (int j = 0; j < nests.size(); j++) {
            QFilter.QFilterNest qFilterNest = nests.get(j);
            String op = qFilterNest.getOp();
            QFilter nFilter = qFilterNest.getFilter();
            if(nFilter == null){
                continue;
            }
            nFilter.__setProperty(propName);
            qFilterList.add(op);
            num = getDataSetFilter(dataSet,qFilterList,nFilter,num);
        }
        qfilterStrList.add(String.join(" ",qFilterList));
    }
    /**
     * 将dataset.filter转换为filter过滤数据
     * @param qFilterList
     * @param qFilter
     * @param num
     * @return
     */
    private static int getDataSetFilter(DataSet dataSet,List<String> qFilterList,QFilter qFilter,int num){
        String property = qFilter.getProperty();
        Object value = qFilter.getValue();

        //判断当前过滤属性在原dataset中是否存在
        if(!Arrays.asList(dataSet.getRowMeta().getFieldNames()).contains(property)){//不存在
            return num;
        }
        //存在
        Class<?> javaType = dataSet.getRowMeta().getField(property).getDataType().getJavaType();
        if(javaType.equals(Date.class)){
//            Date date = DateUtils.parseStrToDateTime(value);
            qFilter.__setValue(javaType.cast(value));//将参数值强转为原来的类型
        }else if(javaType.equals(BigDecimal.class)){
            qFilter.__setValue(value);//将参数值强转为原来的类型
        }else{
            qFilter.__setValue(javaType.cast(value));//将参数值强转为原来的类型
        }
        String cp = qFilter.getCP();
        if(Arrays.asList(qfilterCompareType).contains(cp)){
            qFilterList.add(String.format("%s %s",property,cp));
        }else{
            qFilterList.add(qFilter.toString());
        }
        return num;
    }
    /* ------------------------------------- 添加过滤、排序字段 - End ------------------------------------- */

    /* ------------------------------------- 动态增加字段 - Start ------------------------------------- */
    /**
     * 动态添加多个字段,并加入已经存在的分组中
     * @param columns 报表查询插件getColumns方法的参数
     * @param groupInfoMap 需要添加的分组信息和字段信息
     *          ReportColumnGroup 分组信息
     *          Map<String,String> 需要增加的多个字段
     *              caption 新增字段标题
     *              width 新增字段的宽度
     *              fieldKey 新增字段的标识
     *              columnType 新增字段的类型
     * @return
     */
    public static List<AbstractReportColumn> addNewColumn(List<AbstractReportColumn> columns, Map<ReportColumnGroup,List<ReportColumn>> groupInfoMap){
        groupInfoMap.forEach((k,v) -> {
            String kFieldKey = k.getFieldKey();
            AtomicBoolean isExist = new AtomicBoolean(false);
            columns.stream().filter(col -> col instanceof ReportColumnGroup).forEach(col -> {
                ReportColumnGroup group = (ReportColumnGroup) col;
                String fieldKey = group.getFieldKey();
                if(fieldKey.equals(kFieldKey)){//分组已经存在
                    group.getChildren().addAll(v);
                    isExist.set(true);
                }
            });
            if(!isExist.get()){//不存在当前分组
                k.getChildren().addAll(v);
                columns.add(k);
            }
        });
        return columns;
    }
    /**
     * 动态添加单个字段
     * @param columns 报表查询插件getColumns方法的参数
     * @param caption 新增字段标题
     * @param width 新增字段的宽度
     * @param fieldKey 新增字段的标识
     * @param columnType 新增字段的类型
     * @return
     */
    public static List<AbstractReportColumn> addNewColumn(List<AbstractReportColumn> columns,String caption,String width,String fieldKey,String columnType){
        columns.add(creatReportColumn(caption, width, fieldKey, columnType));
        return columns;
    }
    /**
     * 动态添加多个字段
     * @param columns 报表查询插件getColumns方法的参数
     * @param columnInfoList 需要增加的多个字段
     *           caption 新增字段标题
     *           width 新增字段的宽度
     *           fieldKey 新增字段的标识
     *           columnType 新增字段的类型
     * @return
     */
    public static List<AbstractReportColumn> addNewColumn(List<AbstractReportColumn> columns, List<Map<String,String>> columnInfoList){
        columnInfoList.forEach(k -> columns.add(creatReportColumn(k.get("caption"), k.get("width"), k.get("fieldKey"), k.get("columnType"))));
        return columns;
    }
    /**
     * 创建新的报表字段
     * @param caption 新增字段标题
     * @param width 新增字段的宽度
     * @param fieldKey 新增字段的标识
     * @param columnType 新增字段的类型
     * @return
     */
    public static ReportColumn creatReportColumn(String caption,String width,String fieldKey,String columnType){
        ReportColumn newColumn = new ReportColumn();
        newColumn.setCaption(new LocaleString(caption));
        newColumn.setWidth(new LocaleString(width));
        newColumn.setFieldKey(fieldKey);
        newColumn.setFieldType(columnType);
        return newColumn;
    }
    /**
     * 创建新的报表字段
     * @param map 新增字段信息
     * @return
     */
    public static ReportColumn creatReportColumn(Map<String,String> map){
        ReportColumn newColumn = new ReportColumn();
        newColumn.setCaption(new LocaleString(map.get("caption")));
        newColumn.setWidth(new LocaleString(map.get("width")));
        newColumn.setFieldKey(map.get("fieldKey"));
        newColumn.setFieldKey(map.get("columnType"));
        return newColumn;
    }
    /**
     * 创建新的报表分组字段
     * @param caption 新增字段标题
     * @param fieldKey 新增字段的标识
     * @return
     */
    public static ReportColumnGroup creatReportColumnGroup(String caption,String fieldKey){
        ReportColumnGroup newColumnGroup = new ReportColumnGroup();
        newColumnGroup.setCaption(new LocaleString(caption));
        newColumnGroup.setFieldKey(fieldKey);
//        newColumnGroup.setHideSingleColumnRow(false);//设置只有一个下级分组时是否隐藏下级分组，默认隐藏
        return newColumnGroup;
    }

    /**
     * 创建新的报表分组字段
     * @param caption 新增字段标题
     * @param fieldKey 新增字段的标识
     * @param childrenList 分组下的字段集合
     * @return
     */
    public static ReportColumnGroup creatReportColumnGroup(String caption,String fieldKey,List<ReportColumn> childrenList){
        ReportColumnGroup newColumnGroup = new ReportColumnGroup();
        newColumnGroup.setCaption(new LocaleString(caption));
        newColumnGroup.setFieldKey(fieldKey);
        //        newColumnGroup.setHideSingleColumnRow(false);//设置只有一个下级分组时是否隐藏下级分组，默认隐藏
        childrenList.forEach(k -> newColumnGroup.getChildren().add(k));
        return newColumnGroup;
    }
    /**
     * 创建新的报表分组字段
     * @param map 新增分组信息
     * @return
     */
    public static ReportColumnGroup creatReportColumnGroup(Map<String,Object> map){
        ReportColumnGroup newColumnGroup = new ReportColumnGroup();
        newColumnGroup.setCaption(new LocaleString((String) map.get("caption")));
        newColumnGroup.setFieldKey((String)map.get("fieldKey"));
//        newColumnGroup.setHideSingleColumnRow(false);//设置只有一个下级分组时是否隐藏下级分组，默认隐藏
        ((List<ReportColumn>) map.get("childrenList")).forEach(k -> newColumnGroup.getChildren().add(k));
        return newColumnGroup;
    }
    /* ------------------------------------- 动态增加字段 - End ------------------------------------- */

    public static void removeColumn(List<AbstractReportColumn> columns,String[] needRemoveColumn){
        assert needRemoveColumn != null;
        List<String> needRemoveColumnList = Arrays.asList(needRemoveColumn);
        Iterator<AbstractReportColumn> iterator = columns.iterator();
        while (iterator.hasNext()){
            AbstractReportColumn next = iterator.next();
            String fieldKey = "";
            if(next instanceof ReportColumn){
                fieldKey = ((ReportColumn) next).getFieldKey();
            }else if(next instanceof ReportColumnGroup){
                fieldKey = ((ReportColumnGroup) next).getFieldKey();
            }
            if(needRemoveColumnList.contains(fieldKey)){
                iterator.remove();
            }
        }
    }

    /* ------------------------------------- util - Start ------------------------------------- */
    public static DataSet leftJoinMap(DataSet masterDataset, DataSet leftJoinDataSet, String[] leftAddField,boolean needContent,String... keys){
        Map<String,String> map = new HashMap<>();
        if(keys == null){
            return null;
        }
        int length = keys.length;
        if(length > 1){
            map.put(keys[0],keys[1]);
        }else{
            map.put(keys[0],keys[0]);
        }
        return leftJoinDataSet(masterDataset, leftJoinDataSet, leftAddField, map,needContent);
    }
    /**
     * 连接两个DataSet
     * @param masterDataset
     * @param leftJoinDataSet
     * @param leftAddField
     * @return
     */
    public static DataSet leftJoinDataSet(DataSet masterDataset, DataSet leftJoinDataSet, String[] leftAddField, Map<String,String> leftOnMap,boolean needContent){
        if(masterDataset == null && leftJoinDataSet == null){
            return null;
        }else if(masterDataset == null){
            return leftJoinDataSet;
        }else if(leftJoinDataSet == null){
            return masterDataset;
        }
        boolean masterHasNext = masterDataset.copy().iterator().hasNext();
        boolean leftJoinHasNext = leftJoinDataSet.copy().iterator().hasNext();
        if(masterHasNext && leftJoinHasNext){
            String[] leftFields = masterDataset.getRowMeta().getFieldNames();
            List<String> leftFieldsList = Arrays.asList(leftFields);
            String[] leftJoinFields = leftJoinDataSet.getRowMeta().getFieldNames();
            List<String> leftJoinFieldsList = Arrays.asList(leftJoinFields);
            Set<String> leftAddSet = Arrays.stream(leftJoinFields).filter(k -> leftOnMap.containsValue(k) || !leftFieldsList.contains(k)).collect(Collectors.toSet());
            //将新字段加入到数据中
            if(leftAddField != null){
//                leftAddSet.addAll(Arrays.asList(leftAddField));
                for(String addField : leftAddField){
                    if(leftJoinFieldsList.contains(addField)){
                        leftAddSet.add(addField);
                    }
                }
            }
            int onListLength = 0;
            AtomicInteger atomicInteger = new AtomicInteger();
            atomicInteger.set(onListLength);
            JoinDataSet joinDataSet = masterDataset.copy().leftJoin(leftJoinDataSet.copy());
            if(leftOnMap != null){
                leftOnMap.forEach((k,v) -> {
                    if(leftFieldsList.contains(k) && leftJoinFieldsList.contains(v)){
                        atomicInteger.set(atomicInteger.get() + 1);
                        joinDataSet.on(k,v);
                    }
                });
            }
            if(atomicInteger.get() == 0){
                return masterDataset;
            }
            String[] leftAddArrays = leftAddSet.stream().filter(k -> !leftOnMap.containsValue(k) && !Arrays.asList(leftFields).contains(k)).toArray(String[]::new);

            Map<String,String> leftAddMap = new HashMap<>();
            //数据字段判断
            Arrays.asList(leftAddArrays).forEach(k -> {
                if(k.contains(" as ")){
                    String[] asK = k.split(" ");
                    if(leftAddMap.containsKey(asK[0]) && leftAddMap.get(asK[0]) != null){
                        leftAddMap.put(asK[0],asK[2]);
                    }
                }else{
                    if(!leftAddMap.containsKey(k)){
                        leftAddMap.put(k,null);
                    }
                }

            });
            String[] masterAddArrays = Arrays.stream(leftFields)
                    .filter(k -> !Arrays.asList(leftAddArrays).contains(k) || !leftAddMap.containsKey(k) || !leftAddMap.containsValue(k)).toArray(String[]::new);
            List<String> masterAddList = new ArrayList<>();
            leftAddMap.forEach((k,v) -> {
                masterAddList.add(v == null ? k : String.format("'%s' as '%s'",k,v));
            });
            String[] masterArrays = masterAddList.toArray(new String[0]);
            return joinDataSet.select(masterAddArrays, masterArrays).finish();
        }
        if(needContent && !masterHasNext && leftJoinHasNext){
            return leftJoinDataSet;
        }else{
            return masterDataset;
        }
    }

    /**
     * 合并两个DataSet全部数据
     * @param leftDataSet
     * @param rightDataSet
     * @param groupFields
     * @return
     */
    public static DataSet joinAllDataSet(DataSet leftDataSet,DataSet rightDataSet,String[] groupFields,String priority){
        //1、判断是否为空
        if(leftDataSet == null || rightDataSet == null){
            if("0".equals(priority)){//谁不为空返回谁
                if(leftDataSet == null){
                    return rightDataSet;
                }else{
                    return leftDataSet;
                }
            }else if("1".equals(priority)){//左连接优先
                return leftDataSet;
            }else if("2".equals(priority)){//右连接优先
                return rightDataSet;
            }
        }
        //2、获取两个DataSet字段数据
        String[] leftDataSetFieldNames = leftDataSet.getRowMeta().getFieldNames();
        String[] rightDataSetFieldNames = rightDataSet.getRowMeta().getFieldNames();
        //3、获取两个DataSet分别缺少的字段
        String[] leftNeedAddCol = getArrayIsExist(leftDataSetFieldNames, rightDataSetFieldNames);
        String[] rightNeedAddCol = getArrayIsExist(rightDataSetFieldNames, leftDataSetFieldNames);
        //4、给两个DataSet添加缺少的字段
        leftDataSet = leftDataSet.copy().addNullField(leftNeedAddCol);

        rightDataSet = rightDataSet.copy().addNullField(rightNeedAddCol);
        //修改右连接字段顺序 确保union的时候字段一一对应
        rightDataSet = rightDataSet.copy().select(leftDataSet.getRowMeta().getFieldNames());
        //5、连接两个DataSet
        DataSet dataSetUnion = leftDataSet.copy().union(rightDataSet.copy());
        String[] dataSetUnionFieldNames = dataSetUnion.getRowMeta().getFieldNames();
        //6、根据分组并合并数据
        GroupbyDataSet unionDataSetGroupBy = dataSetUnion.copy().select(dataSetUnionFieldNames).groupBy(groupFields);
        AtomicReference<GroupbyDataSet> unionAtomic = new AtomicReference<>();
        unionAtomic.set(unionDataSetGroupBy);
        Arrays.stream(dataSetUnionFieldNames).filter(kf -> !Arrays.asList(groupFields).contains(kf)).forEach(k -> {
            unionAtomic.set(unionAtomic.get().sum(k));
        });
        return unionAtomic.get().finish();
    }

    /**
     * 获取在secArrays存在，但是firstArrays不存在的值
     * @param firstArrays
     * @param secArrays
     * @return
     */
    public static String[] getArrayIsExist(String[] firstArrays,String[] secArrays){
        return Arrays.stream(secArrays).filter(k -> !Arrays.asList(firstArrays).contains(k)).toArray(String[]::new);
    }

    /**
     * DataSet 从行转成列
     * @param rowDataSet 需要从行转成列的DataSet - 默认DataSet的字段和类型完全一致
     *           例：DataSet [a,b][类型1，值1]
     *              DataSet [a,b][类型2，值2]
     *              DataSet [a,b][类型3，值3]
     *              DataSet [a,b][类型4，值4]
     * @param newReportColumnList 需要新增的字段信息
     * @param masterGroupStr 主分组字段
     * @param colGroupStr 需要作为表头字段的字段
     * @param colFilter 需要展示的数据条件
     * @param thenStr 需要展示的数据为真的情况
     * @param elseStr 需要展示的数据为假的情况
     * @param ruleType 新增字段命名规则格式
     * @param nameColStr 新增字段需要展示报表上的字段信息时，需要展示的字段标识
     * @param nameKeyStr  新增字段命名别称
     * @param nameFormatStr 新增字段命名规则格式
     * @param colType 新增字段的报表类型
     * @return
     */
    public static DataSet rowToCol(DataSet rowDataSet,List<ReportColumn> newReportColumnList,String masterGroupStr,String colGroupStr,//分组信息
                                   String colFilter,String thenStr,String elseStr,//行转列条件
                                   String ruleType,String nameColStr,String nameKeyStr,String nameFormatStr,String colType){//新增字段命名参数
        if(rowDataSet == null){
            return null;
        }
        //1、将行数据列化
        DataSet isColDataSet = rowDataSet.copy()
                .groupBy(StringUtils.isEmpty(nameColStr) ? new String[]{colGroupStr,masterGroupStr} : new String[]{colGroupStr,masterGroupStr,nameColStr})
                .sum(String.format("case when %s then %s else %s end",colFilter,thenStr,elseStr), "newcol").finish();
        //2、获取行转列后的需要添加的列信息
        int num = 0;
        DataSet colMapDataSet = isColDataSet.copy();
        Map<Object,String> colMap = new HashMap<>();
        Iterator<Row> testIterator = colMapDataSet.iterator();
        while (testIterator.hasNext()){
            Row next = testIterator.next();
            Object pronumber = next.get(colGroupStr);
            if(!colMap.containsKey(pronumber)){//不存在当前字段
                num++;
                String randomStr = ReportTableHeadHelper.getRandomStr(10);
                String columnName = getColumnNameRule(ruleType, nameKeyStr, num, nameFormatStr, next, nameColStr);
                newReportColumnList.add(creatReportColumn(columnName,"50",randomStr,colType));
                colMap.put(pronumber,randomStr);
            }
        }
        Map<String,String> onMap = new HashMap<>();
        onMap.put(masterGroupStr,masterGroupStr);
        onMap.put(colGroupStr,colGroupStr);
        //3、根据主分组字段和副分组字段，创建新列信息
        //这个时候的数据结构为：
        //row1[master col newcol1 newcol2 newcol3]
        // ["master1","col1","newvalue11", "",             ""]
        // ["master1","col1",null,        "newvalue12",    ""]
        // ["master1","col1",null,        "",             "newvalue13"]
        //row2[master col newcol1 newcol2 newcol3]
        // ["master2","col2","newvalue21", "",             ""]
        // ["master2","col2",null,        "newvalue22",    ""]
        // ["master2","col2",null,        "",             "newvalue23"]
        AtomicReference<DataSet> oldataSetAtomic = new AtomicReference<>();
        oldataSetAtomic.set(isColDataSet.copy());
        AtomicReference<DataSet> dataSetAtomic = new AtomicReference<>();
        dataSetAtomic.set(isColDataSet.copy());
        colMap.forEach((k,v) -> {
            if(k != null){
                //生成新dataset
                DataSet newSelectDataSet = oldataSetAtomic.get().copy().filter(String.format(k instanceof String ? "%s = '%s'" : "%s = %s",colGroupStr,k))
                        .select("newcol as " + v + "", colGroupStr, masterGroupStr);
                //连接数据
                dataSetAtomic.set(ReportTableHeadHelper.leftJoinDataSet(dataSetAtomic.get(),newSelectDataSet,new String[]{v},onMap,false));
            }else {//为空，不新增列数据
                Iterator<ReportColumn> newReportColumnIterator = newReportColumnList.iterator();
                while (newReportColumnIterator.hasNext()){
                    ReportColumn next = newReportColumnIterator.next();
                    if(next.getFieldKey().equals(v)){
                        newReportColumnIterator.remove();
                        break;
                    }
                }
            }
        });
        DataSet dataSet = dataSetAtomic.get();
        //4、合并同主分组数据 将3步骤获取到的数据合并为以下结构
        //row1[master col newcol1 newcol2 newcol3]
        // ["master1","col1","newvalue11", "newvalue12", "newvalue13"]
        //row2[master col newcol1 newcol2 newcol3]
        // ["master2","col2","newvalue21", "newvalue22", "newvalue23"]
        String[] fieldNames = dataSet.getRowMeta().getFieldNames();
        AtomicReference<GroupbyDataSet> groupbyDataSet = new AtomicReference<>();
        groupbyDataSet.set(dataSet.copy().select(String.join(",",fieldNames)).groupBy(new String[]{masterGroupStr}));
        colMap.values().stream().filter(kf -> Arrays.asList(fieldNames).contains(kf)).forEach(k -> {
            groupbyDataSet.set(groupbyDataSet.get().sum(k));
        });
        return groupbyDataSet.get().finish();
    }

    /**
     * DataSet 从行转成列
     * @param rowDataSet 需要从行转成列的DataSet - 默认DataSet的字段和类型完全一致
     *           例：DataSet [a,b][类型1，值1]
     *              DataSet [a,b][类型2，值2]
     *              DataSet [a,b][类型3，值3]
     *              DataSet [a,b][类型4，值4]
     * @param newReportColumnList 需要新增的字段信息
     * @param nameRuleType 新增字段命名规则类型
     * @param keyFormat 新增字段命名规则格式
     * @return
     */
    public static Map<String,String> getRowToColInfo(DataSet rowDataSet,String fieldFilter,List<ReportColumn> newReportColumnList,String nameRuleType,String nameProType,String keyFormat,String selfCol){
        //1、获取分类的所有类型
        Map<String,String> typeMap = new HashMap<>();
        int rowsSizeLength = 0;
        Iterator<Row> iterator = rowDataSet.copy().iterator();
        while (iterator.hasNext()){
            Row next = iterator.next();
            Object o = next.get(fieldFilter);
            String fieldCol;
            if(o instanceof DynamicObject){
                try {
                    fieldCol = ((DynamicObject) o).getString("number");
                }catch (KDException k){
                    fieldCol = ((DynamicObject) o).getString("billno");
                }
            }else {
                fieldCol = String.valueOf(o);
            }
            if(!typeMap.containsKey(fieldCol)){
                //随机生成字段key值
                String fieldKey = getRandomStr(10);
                typeMap.put(fieldCol,fieldKey);
                boolean isExist = true;
                //判断是否存在key
                for (ReportColumn reportColumn : newReportColumnList) {
                    if(reportColumn.getFieldKey().equals(fieldKey)){//已经存在
                        isExist = false;
                        break;
                    }
                }
                if(isExist){//不存在，需要新建
                    rowsSizeLength++;
                    newReportColumnList.add(creatReportColumn(getColumnNameRule(nameProType, fieldCol, rowsSizeLength, keyFormat,next,selfCol),"50",fieldKey,nameRuleType));
                }
            }
        }
        return typeMap;
    }
    /**
     * DataSet 从行转成列
     * @param rowDataSet 需要从行转成列的DataSet - 默认DataSet的字段和类型完全一致
     *           例：DataSet [a,b][类型1，值1]
     *              DataSet [a,b][类型2，值2]
     *              DataSet [a,b][类型3，值3]
     *              DataSet [a,b][类型4，值4]
     * @param fieldName 列字段分类
     *           例：a
     * @return
     */
    public static DataSet setRowInfoToColInfo(DataSet rowDataSet,String fieldName,String fieldFilter,String fieldValue,Map<String,String> typeMap){
        Map<String,String> map = new HashMap<>();
        map.put(fieldName,fieldName);
        //重新创建
        String[] resultDataSetFieldNames = rowDataSet.getRowMeta().getFieldNames();

        DataSet resultDataSet = null;
        for(String type : typeMap.keySet()){
                if(StringUtils.isEmpty(type)){
                continue;
            }
            String fieldKey = typeMap.get(type);
            List<String> newColumn = new ArrayList<>();
            Arrays.stream(resultDataSetFieldNames).forEach(k -> {
                newColumn.add(k.equals(fieldFilter) ? String.format("%s as %s",fieldValue,fieldKey) : k);
            });
            DataSet typeDataSet = rowDataSet.copy().filter(String.format("%s = '%s'", fieldFilter, type)).select(String.join(",",newColumn));
            if(resultDataSet == null){
                resultDataSet = typeDataSet;
            }else{
                String[] typeDataSetFieldNames = typeDataSet.getRowMeta().getFieldNames();
                if(Arrays.asList(resultDataSetFieldNames).contains(type)){//已经存在，就判断两个字段数量，不足添加，然后使用union连接
                    Arrays.stream(resultDataSetFieldNames).filter(kf -> !Arrays.asList(typeDataSetFieldNames).contains(kf))
                            .forEach(typeDataSet::addNullField);
                    resultDataSet = resultDataSet.union(typeDataSet);
                }else {//不存在，使用leftjoin连接
                    resultDataSet = leftJoinDataSet(resultDataSet, typeDataSet, new String[]{String.format("%s as %s", fieldValue, fieldKey)}, map,false);
                }
            }
        }
        return resultDataSet;
    }

    /**
     * 修改、替换过滤条件的值
     * @param filter
     * @param fieldName
     * @param fieldCp
     * @param fieldValue
     * @return
     */
    public static QFilter changeQFilter(QFilter filter,String fieldName,String fieldCp,Object fieldValue){
        String property = filter.getProperty();
        if(property.equals(fieldName)){
            filter.__setCP(fieldCp);
            filter.__setValue(fieldValue);
        }else{
            boolean isExist = false;
            List<QFilter.QFilterNest> nests = filter.getNests(true);
            for (int j = 0; j < nests.size(); j++) {
                QFilter.QFilterNest qFilterNest = nests.get(j);
                QFilter nFilter = qFilterNest.getFilter();
                if(nFilter == null){
                    continue;
                }
                String nProperty = nFilter.getProperty();
                if(nProperty.equals(fieldName)){
                    nFilter.__setValue(fieldValue);
                    nFilter.__setCP(fieldCp);
                    isExist = true;
                    break;
                }
            }
            if(!isExist){
                filter.and(fieldName, fieldCp,fieldValue);
            }
        }
        return filter;
    }

    /**
     * 字段命名规则
     * 命名示例：
     * 1、ruleType = A    keyFormat = "mynameis%s"       key = "param"
     *      return mynameisparam
     * 2、ruleType = B    keyFormat = "mynameis%s"       keyNum = 1
     *      return mynameis1
     * 3、ruleType = C   keyFormat = "%s%s"    key = "param"   keyNum = 1
     *      return param1
     * 4、ruleType = D   keyFormat = "%s%s"    key = "param"   keyNum = 1
     *      return 1param
     * 5、ruleType = E   keyFormat = "%s%s"    key = "param"
     *      return param
     * 6、ruleType = F   next = dataset.iterator.next    selfCol = dataset.getRowMeta().getFieldNames()[0]
     *      return next.getString(selfCol)
     * 7、ruleType = default    key = "param"
     *      return 项目param
     * @param ruleType 命名规则类型
     * @param key 命名新值
     * @param keyNum key值下标
     * @param keyFormat 命名格式
     * @param next dataset元素
     * @param selfCol 需要查询的字段
     * @return
     */
    public static String getColumnNameRule(String ruleType, String key, int keyNum, String keyFormat, Row next, String selfCol){
        String columnName;
        switch (ruleType){
            case "A":
                columnName = String.format(keyFormat,key);
                break;
            case "B":
                columnName = String.format(keyFormat,keyNum);
                break;
            case "C":
                columnName = String.format(keyFormat,key,keyNum);
                break;
            case "D":
                columnName = String.format(keyFormat,keyNum,key);
                break;
            case "E":
                columnName = key;
                break;
            case "F":
                columnName = next.getString(selfCol);
                break;
            default:
                columnName = String.format(ResManager.loadKDString("项目%s","ReportTableHeadHelper_1","ats-core-common"),key);
        }
        return columnName;
    }
    /**
     * 随机生成n个字符
     * @param strSize 字符长度
     * @return
     */
    public static String getRandomStr(Integer strSize){
        StringBuilder stringBuilder = new StringBuilder();
        //1、设置组合字段
        String charArray = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        char[] chars = charArray.toCharArray();
        //2、每一位随机数设置
        for (Integer i = 0; i < strSize; i++) {
            int i1 = (int) Math.round(Math.random() * 51);
            char aChar = chars[i1];
            stringBuilder.append(aChar);
        }
        return stringBuilder.toString();
    }
    /* ------------------------------------- util - query - bill - Start ------------------------------------- */
    /**
     * 获取报表过滤值
     * @param queryParam 报表查询参数
     * @param rptPro 报表查询字段标识
     * @return
     */
    public static Object getQfilterValue(ReportQueryParam queryParam,String rptPro){
        return queryParam.getFilter().getValue(rptPro);
    }
    /**
     * 获取报表DynamicObject过滤
     * @param queryParam 报表查询参数
     * @param rptPro 报表查询字段标识
     * @param qfilterPro 需要查询的对象标识
     * @return
     */
    public static QFilter getDyQfilter(ReportQueryParam queryParam,String rptPro,String qfilterPro){
        Object obj = queryParam.getFilter().getValue(rptPro);
        if(obj != null){
            if (obj instanceof List) {
                QFilter qFilter=null;
                for (Object o:(List)obj) {
                    if(qFilter==null){
                        qFilter =QFilter.of(String.format("%s.id = ?",qfilterPro),((DynamicObject) o).getLong("id"));
                    }else {
                        qFilter.or(QFilter.of(String.format("%s.id = ?", qfilterPro), ((DynamicObject) o).getLong("id")));
                    }
                }
                return qFilter;
            } else {
                return QFilter.of(String.format("%s.id = 0",qfilterPro));
            }
        }else{
            return QFilter.of("1 = 1");
        }
    }
    /**
     * 获取报表DynamicObject过滤
     * @param queryParam 报表查询参数
     * @param biginQryStr 报表查询字段开始日期标识
     * @param endQryStr 报表查询字段结束日期标识
     * @param qfilterDatePro 需要查询的对象日期标识
     * @return
     */
    public static QFilter getDateRangeQfilter(ReportQueryParam queryParam,String biginQryStr,String endQryStr,String qfilterDatePro){
        QFilter qFilter = QFilter.of("1=1");
        Object bizdatebeginqryObj = queryParam.getFilter().getValue(biginQryStr);//开始标识
        if(bizdatebeginqryObj instanceof Date){
            qFilter.and(qfilterDatePro, QCP.large_equals,bizdatebeginqryObj);
        }
        Object bizdateendqryObj = queryParam.getFilter().getValue(endQryStr);//结束标识
        if(bizdateendqryObj instanceof Date){
            qFilter.and(qfilterDatePro, QCP.less_equals,bizdateendqryObj);
        }
        return qFilter;
    }
    private static Calendar getCalendar(Date date){
        if(date == null){
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * 获取报表多选基础资料过滤
     * @param queryParam 报表查询参数
     * @param mulDyQryStr 需要查询的多选基础资料对象标识
     * @param qfilterPro 需要查询的对象标识
     * @return
     */
    public static QFilter getMulDyQfilter(ReportQueryParam queryParam,String mulDyQryStr,String qfilterPro){
        Object obj = queryParam.getFilter().getValue(mulDyQryStr);//多选基础资料
        if(obj instanceof DynamicObjectCollection){
            Set<Long> mulSet = new HashSet<>();
            ((DynamicObjectCollection) obj).forEach(k -> {
                DynamicObject fbasedataid = k.getDynamicObject("fbasedataid");
                if(fbasedataid != null){
                    mulSet.add( fbasedataid.getLong("id"));
                }
            });
            return new QFilter(String.format("%s.id",qfilterPro),QCP.in,mulSet);
        }else {
            return QFilter.of("1 = 1");
        }
    }
    /**
     * 获取报表基础资料集合过滤
     * @param queryParam 报表查询参数
     * @param dyCoQryStr 需要查询的多选基础资料对象标识
     * @param qfilterPro 需要查询的对象标识
     * @return
     */
    public static QFilter getDyCoQfilter(ReportQueryParam queryParam,String dyCoQryStr,String qfilterPro){
        Object obj = queryParam.getFilter().getValue(dyCoQryStr);//多选基础资料
        if(obj instanceof DynamicObjectCollection){
            Set<Long> mulSet = new HashSet<>();
            ((DynamicObjectCollection) obj).forEach(k -> mulSet.add(k.getLong("id")));
            return new QFilter(String.format("%s.id",qfilterPro),QCP.in,mulSet);
        }else {
            return QFilter.of("1 = 1");
        }
    }
    /**
     * 获取报表字段过滤
     * @param queryParam 报表查询参数
     * @param colQryStr 需要查询的多选基础资料对象标识
     * @param qfilterPro 需要查询的对象标识
     * @return
     */
    public static QFilter getColQfilter(ReportQueryParam queryParam,String colQryStr,String qfilterPro){
        Object obj = queryParam.getFilter().getValue(colQryStr);//多选基础资料
        if(obj != null){
            return new QFilter(qfilterPro,QCP.equals,obj);
        }else {
            return QFilter.of("1 = 1");
        }
    }
    /**
     * 添加新字段至查询数组中
     * @param oldArrays
     * @param newCol
     * @return
     */
    public static String[] addNewSelectors(String[] oldArrays,String... newCol){
        List<String> newList = new ArrayList<>(Arrays.asList(oldArrays));
        newList.addAll(Arrays.asList(newCol));
        return newList.toArray(new String[0]);
    }
    /**
     * 添加求和字段
     * @param dataSet
     * @param sumName 求和字段别名
     * @param needSumCol 需要添加的求和字段数组
     * @return
     */
    public static DataSet addNewColSum(DataSet dataSet,String sumName,String... needSumCol){
        String needSumColStr = String.format("%s as %s",String.join("+",needSumCol),sumName);
        if(dataSet != null){
            dataSet = dataSet.copy().select(addNewSelectors(dataSet.getRowMeta().getFieldNames(),needSumColStr));
        }
        return dataSet;
    }
    /**
     * 添加除数字段
     * @param dataSet
     * @param numerator 分子
     * @param denominator 分母
     * @param divName 别名
     * @return
     */
    public static DataSet addNewColDiv(DataSet dataSet,String numerator,String denominator,String divName,int cast){
        String totalStr = String.format("round(cast(%s as BigDecimal)/cast(%s as BigDecimal),%s) as %s",numerator,denominator,cast,divName);
        if(dataSet != null){
            dataSet = dataSet.copy().select(ReportTableHeadHelper.addNewSelectors(dataSet.getRowMeta().getFieldNames(), totalStr));
        }
        return dataSet;
    }

    /**
     * 创建空DataSet
     * @return
     */
    public static  DataSet createNullDataSet(String algo,String pk){
        //创建空DataSet
        Collection<Object[]> coll = new ArrayList<>();
        RowMeta rowMeta = RowMetaFactory.createRowMeta(new String[]{pk}, new DataType[]{DataType.StringType});
        CollectionInput input = new CollectionInput(rowMeta,coll);
        return Algo.create(algo).createDataSet(input);
    }
    /**
     * 创建空DataSet
     * @return
     */
    public static  DataSet createNullDataSet(String algo,String[] pkArray,DataType[] typeArray){
        //创建空DataSet
        Collection<Object[]> coll = new ArrayList<>();
        RowMeta rowMeta = RowMetaFactory.createRowMeta(pkArray, typeArray);
        CollectionInput input = new CollectionInput(rowMeta,coll);
        return Algo.create(algo).createDataSet(input);
    }

    /* ------------------------------------- util - query - bill - End ------------------------------------- */
    /* ------------------------------------- util - End ------------------------------------- */
}